#pragma once

#include <iostream>
#include <vector>
#include <functional>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>

#include "Inet_Addr.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "LockGuard.hpp"

using namespace LogModule;

using task_t = std::function<void(void)>; // 包装一个线程的任务函数

class Route
{
private:
    void Check(Int_Addr &who)
    {
        LockGuard lockguard(&_mutex);
        for (auto &user : _online_users)
        {
            if (user == who)
                return; // 用户已经存在
        }
        // 不存在，添加
        _online_users.emplace_back(who);
        LOG(DEBUG, "%s add success\n", who.AddrStr().c_str());
    }

    void Offline(Int_Addr &who)
    {
        LockGuard lockguard(&_mutex);
        auto iter = _online_users.begin();
        for (; iter != _online_users.end(); iter++)
        {
            if (*iter == who)
            {
                LOG(DEBUG, "%s remove success\n", who.AddrStr().c_str());
                _online_users.erase(iter);
                break; // 避免迭代器失效
            }
        }
    }

    void ForwardHelper(int sockfd, std::string message, Int_Addr &who)
    {
        LockGuard lockguard(&_mutex);
        std::string send_message = "[" + who.AddrStr() + "]# " + message;
        // 转发
        for (auto &user : _online_users)
        {
            struct sockaddr_in peer = user.Addr(); // 发给谁
            ::sendto(sockfd, send_message.c_str(), send_message.size(), 0, (struct sockaddr *)&peer, sizeof(peer));
            LOG(INFO, "%s forward a message is %s\n", who.AddrStr(), send_message.c_str());
        }
    }

public:
    Route()
    {
        pthread_mutex_init(&_mutex, nullptr);
    }

    void Forward(int sockfd, std::string message, Int_Addr &who)
    {
        // 1、检查用户是否在，在线列表 ---》a.不在：添加  b.在：啥都不做
        Check(who);
        // 2、用户需要离线离线
        if (message == "QUIT" || message == "Q")
        {
            Offline(who);
        }
        // 3、向你在线的用户转发消息
        //    让线程去转发
        task_t t = std::bind(&Route::ForwardHelper, this, sockfd, message, who);
        ThreadPool<task_t>::getInstance()->PushTask(t);
    }

    ~Route()
    {
        pthread_mutex_destroy(&_mutex);
    }

private:
    std::vector<Int_Addr> _online_users; // 在线用户列表
    pthread_mutex_t _mutex;              // 互斥锁
};